#include "liolib/lioflat.h"

int scan=-1,shift=5,count=500,accum=0,accum0=10,count_calc=0,count_real=0,cluster=0;
double t=0,s=0,dev=1,beta=0.1,sample=1,R_real,R_estim,R_accum,ratio=0.1,ratio_calc;

class GMP:public FlatApplication
{
	enum EnumProcessChnl{	
		CHNL_PROCESS_TIME,
		CHNL_PROCESS_GMP,
		CHNL_PROCESS_COUNT};
	enum EnumCorrelChnl{	
		CHNL_CORREL_SHIFT,
		CHNL_CORREL_REAL,
		CHNL_CORREL_ESTIM,
		CHNL_CORREL_ACCUM,
		CHNL_CORREL_COUNT};
	Font fontSmall;
	FlatText tbDev,tbBeta,tbSample,tbScan,tbShift,tbCount,tbAccum,tbRatio;
	FlatLabel lDev,lBeta,lSample,lScan,lShift,lCount,lAccum,lRatio;
	FlatButton bApply, bReset, bShow, bFull, bExit;
	FlatGraph fgProcess,fgCorrel;
	Vector<double> data;
	GaussMarkov gmp_real,gmp_estim,gmp_accum;
	SignalStat stat,mBeta,mDev,varR;
	Channel *chnlProcess[CHNL_PROCESS_COUNT],*chnlCorrel[CHNL_CORREL_COUNT];
	void reset()
	{
		mBeta.clear();
		mDev.clear();
		varR.clear();
	}
	void getValues()
	{
		scan=format.toInt(tbScan.text);
		shift=format.toInt(tbShift.text);
		count=format.toInt(tbCount.text);
		dev=format.toDouble(tbDev.text);
		beta=format.toDouble(tbBeta.text);
		sample=format.toDouble(tbSample.text);
		accum=accum0=format.toInt(tbAccum.text);
		ratio=format.toDouble(tbRatio.text);

		updateChannels();
	}
	void setValues()
	{
		tbScan.text=format.toString(scan);
		tbShift.text=format.toString(shift);
		tbCount.text=format.toString(count);
		tbDev.text=format.toString(dev);
		tbBeta.text=format.toString(beta);
		tbSample.text=format.toString(sample);
		tbAccum.text=format.toString(accum0);
		tbRatio.text=format.toString(ratio);
	}
	void updateChannels()
	{
		chnlProcess[CHNL_PROCESS_TIME]->setSource(&t,count);
		chnlProcess[CHNL_PROCESS_GMP]->setSource(&gmp_real.x,count);
		chnlCorrel[CHNL_CORREL_SHIFT]->setSource(&s,shift);
		chnlCorrel[CHNL_CORREL_REAL]->setSource(&R_real,shift);
		chnlCorrel[CHNL_CORREL_ESTIM]->setSource(&R_estim,shift);
		chnlCorrel[CHNL_CORREL_ACCUM]->setSource(&R_accum,shift);
	}
	void apply();
	BOOL create();
	void update();
	void draw2D();
	BOOL listen(WORD id, WORD code, const void *info);
	
} gmp;
void GMP::apply()
{
	if(!count||!shift||!dev)
		return;
	gmp_real.init(dev,beta,sample);
	count_real=gmp_real.getSamples(ratio);
	data.setSize(count);
	t=s=0;
	stat.clear();
	if(bShow.checked)
	{
		fgProcess.graph.clear();
		for(int i=0;i<count;i++)
		{
			fgProcess.graph.addValues();
			t+=sample;
			data[i]=gmp_real.next();
			stat.add(gmp_real.x);
		}
		fgProcess.graph.update();
	}
	else
	{
		for(int i=0;i<count;i++)
			data[i]=gmp_real.next();
	}
	if(!gmp_estim.init(data,NULL,count,shift,sample,0,scan))
		return;
	mBeta.add(gmp_estim.beta);
	mDev.add(gmp_estim.stdev);
	varR.add(gmp_estim.R[shift-1]);
	ratio_calc=sqrt(varR.var())/(dev*dev);
	gmp_accum.init(mDev.mean(),mBeta.mean(),sample);
	count_calc=gmp_accum.getSamples(ratio);
	fgCorrel.graph.clear();
	for(int i=0;i<shift;i++)
	{
		R_real=gmp_real.autocorrel(s);
		R_estim=gmp_estim.autocorrel(s);
		R_accum=gmp_accum.autocorrel(s);
		fgCorrel.graph.addValues();
		s+=sample;
	}
	fgCorrel.graph.update();
}
BOOL GMP::listen(WORD id, WORD code, const void *info)
{
	if(	id==bApply.id||
		id==tbBeta.id||
		id==tbSample.id||
		id==tbScan.id||
		id==tbShift.id||
		id==tbDev.id||
		id==tbCount.id||
		id==tbAccum.id||
		id==tbRatio.id)
	{
        if(code==FLAT_ACTION_DEFAULT)
		{
			HCURSOR oldCursor=setCursor(IDC_WAIT);
			getValues();
			setValues();
			if(bReset.checked)
				reset();
			apply();
			SetCursor(oldCursor);
			return TRUE;
		}
	}
	else if(id==bExit.id)
	{
		if(code==FLAT_ACTION_DEFAULT)
		{
			terminate();
			return TRUE;
		}
	}
	else if(id==fgProcess.id)
	{
		if(code==FLAT_ACTION_SELECT)
		{
			if(fgProcess.graph.marked&&fgProcess.graph.marked->length>1)
			{
				double ratio=double(fgProcess.graph.mark)/(fgProcess.graph.marked->length-1);
				tbCount.setText(format.toString(count*ratio));
			}
			return TRUE;
		}
	}
	else if(id==fgCorrel.id)
	{
		if(code==FLAT_ACTION_SELECT)
		{
			if(fgCorrel.graph.marked&&fgCorrel.graph.marked->length>1)
			{
				double ratio=double(fgCorrel.graph.mark)/(fgCorrel.graph.marked->length-1);
				tbShift.setText(format.toString(round(ratio*(shift-1)+1)));
			}
			return TRUE;
		}
	}
	else if(id==bFull.id)
	{
		toggleFullscreen();
		return TRUE;
	}
	return FALSE;
}
BOOL GMP::create ()				
{
	FlatApplication::create();
	name=_T("Gauss-Markov Process Observer");

	format.precision=3;

	fontSmall.setFace(_T("Courier New"));
	fontSmall.height=-12;
	add(&fontSmall);

	fd.addFilter(_T("dat"),_T("Matlab Data File"));
	fd.addFilter(_T("*"),_T("All Files"));

	fgProcess.bgColor=INT_GRAY;
	fgProcess.graph.grid.set(3,5);
	fgProcess.graph.margin=10;
	fgProcess.graph.marginChannel.set(15,40);
	fgProcess.graph.font=&fontSmall;
	fgProcess.graph.formatX.precision=2;
	fgProcess.graph.formatY.precision=2;
	fgProcess.setBounds(330,10,460,240);
	fgProcess.margin.set(5,5);
	fgProcess.fontColor=INT_BLACK;

	fgCorrel.copy(fgProcess);
	fgCorrel.graph.marginChannel.set(15,50);
	fgCorrel.stick(DIR_DOWN,0,5,&fgProcess);
	fgCorrel.size.set(460,340);

	lDev.text=_T("Stddev:");
	lDev.fontColor=INT_WGRAY;
	lDev.margin.set(5,1);
	lDev.location.set(10,60);
	lDev.adjustSize=TRUE;

	lBeta.text=_T("Beta:");
	lBeta.copy(lDev);
	lBeta.stick(DIR_DOWN,0,5);

	lSample.text=_T("Sample:");
	lSample.copy(lBeta);
	lSample.stick(DIR_DOWN,0,5);

	lScan.text=_T("Scan:");
	lScan.copy(lBeta);
	lScan.stick(DIR_DOWN,0,5);

	lShift.text=_T("Shift:");
	lShift.copy(lBeta);
	lShift.stick(DIR_DOWN,0,5);

	lCount.text=_T("Count:");
	lCount.copy(lBeta);
	lCount.stick(DIR_DOWN,0,5);

	lAccum.text=_T("Accum:");
	lAccum.copy(lBeta);
	lAccum.stick(DIR_DOWN,0,5);

	lRatio.text=_T("Ratio:");
	lRatio.copy(lBeta);
	lRatio.stick(DIR_DOWN,0,5);

	bApply.text=_T("Apply");
	bApply.symbol='a';
	bApply.borderLine=1;
	bApply.borderColor=INT_GRAY;
	bApply.activeLine=2;
	bApply.font=&font;
	bApply.fontColor=INT_BLACK;
	bApply.margin.set(20,3);
	bApply.bgColor=0xFFDDDDDD;
	bApply.overColor=INT_WHITE;
	bApply.pressColor=INT_YELLOW;
	bApply.stick(DIR_RIGHT,20,0,&tbDev);
	bApply.adjustSize=TRUE;

	bReset.text=_T("Reset");
	bReset.copy(bApply);
	bReset.margin.set(10,3);
	bReset.checkable=TRUE;
	bReset.checked=TRUE;
	bReset.pressColor=INT_CYAN;
	bReset.stick(DIR_DOWN,0,5,&bApply);

	bShow.text=_T("Show");
	bShow.copy(bReset);
	bShow.checked=TRUE;
	bShow.stick(DIR_DOWN,0,5);

	bFull.text=_T("Fullscr");
	bFull.symbol='f';
	bFull.copy(bReset);
	bFull.checked(createFullScreen);
	bFull.stick(DIR_DOWN,0,5);

	bExit.text=_T("Exit");
	bExit.copy(bApply);
	bExit.pressColor=INT_WRED;
	bExit.stick(DIR_DOWN,0,5);

	tbDev.borderLine=1;
	tbDev.borderColor=INT_WGRAY;
	tbDev.activeLine=2;
	tbDev.font=&font;
	tbDev.fontColor=INT_BLACK;
	tbDev.margin.set(2,1);
	tbDev.setBounds(120,60,70,0);

	tbBeta.copy(tbDev);
	tbBeta.stick(DIR_DOWN,0,5);

	tbSample.copy(tbBeta);
	tbSample.stick(DIR_DOWN,0,5);

	tbRatio.copy(tbBeta);
	tbRatio.stick(DIR_DOWN,0,5);

	tbScan.copy(tbBeta);
	tbScan.size.x=50;
	tbScan.stick(DIR_DOWN,0,5);

	tbShift.copy(tbScan);
	tbShift.stick(DIR_DOWN,0,5);

	tbCount.copy(tbScan);
	tbCount.size.x+=20;
	tbCount.stick(DIR_DOWN,0,5);

	tbAccum.copy(tbScan);
	tbAccum.stick(DIR_DOWN,0,5);
	
	chnlProcess[CHNL_PROCESS_TIME]=fgProcess.graph.addChannel( _T("time"),NULL,INT_WHITE);
	chnlProcess[CHNL_PROCESS_GMP]=fgProcess.graph.addChannel( _T("P real"),_T("time"),INT_BLUE);

	chnlCorrel[CHNL_CORREL_SHIFT]=fgCorrel.graph.addChannel( _T("shift"),NULL,INT_WHITE);
	chnlCorrel[CHNL_CORREL_REAL]=fgCorrel.graph.addChannel( _T("R real"),_T("shift"),INT_BLUE);
	chnlCorrel[CHNL_CORREL_ESTIM]=fgCorrel.graph.addChannel( _T("R estim"),_T("shift"),INT_RED);
	chnlCorrel[CHNL_CORREL_ACCUM]=fgCorrel.graph.addChannel( _T("R accum"),_T("shift"),INT_DGREEN);

	add(&fgProcess);
	add(&fgCorrel);

	add(&lDev);
	add(&lBeta);
	add(&lSample);
	add(&lRatio);
	add(&lScan);
	add(&lShift);
	add(&lCount);
	add(&lAccum);

	add(&bApply);
	add(&bReset);
	add(&bShow);
	add(&bFull);
	add(&bExit);

	add(&tbDev);
	add(&tbBeta);
	add(&tbSample);
	add(&tbRatio);
	add(&tbScan);
	add(&tbShift);
	add(&tbCount);
	add(&tbAccum);

	setValues();
	updateChannels();

	return TRUE;
}
void GMP::update()
{
	if(accum>0)
	{
		accum--;
		if(!accum)
		{
			tbAccum.text=format.toString(accum0);
			tbCount.text=format.toString(count_calc);
		}
		else
		{
			tbAccum.text=format.toString(accum);
		}
		apply();
		updated=TRUE;
	}
}
void GMP::draw2D()
{
	font.color=INT_WHITE;
	font.x=10;
	font.y=20;
	glPrint(&font,name);
	
	font.color=INT_WGRAY;
	font.y=300;
	glPrint(&font,_T("process mean: %.3f"),stat.mean());
	font.y+=18;
	glPrint(&font,_T("process dev:  %.3f"), sqrt(stat.var()));
	font.y+=18;
	glPrint(&font,_T("used scan:    %d"), gmp_estim.realScan);
	font.color=INT_WHITE;
	font.y+=18;
	glPrint(&font,_T("estim count:  %d"), count_calc);
	font.y+=18;
	glPrint(&font,_T("real count:   %d"), count_real);
	font.color=INT_MAGENTA;
	font.y+=18;
	glPrint(&font,_T("calc ratio:   %.3f"), ratio_calc);
	font.y+=18;
	if(ratio<ratio_calc)
	{
		font.color=INT_RED;
		glPrint(&font,_T("              BAD"));
	}
	else
	{
		font.color=INT_GREEN;
		glPrint(&font,_T("              OK"));
	}
	double dbeta,ddev;
	dbeta=gmp_estim.beta-gmp_real.beta;
	ddev=gmp_estim.stdev-gmp_real.stdev;
	font.color=INT_YELLOW;
	font.y+=20;
	glPrint(&font,_T("estim beta:   %.3f"), gmp_estim.beta);
	font.color=INT_ORANGE;
	font.y+=18;
	glPrint(&font,_T("     error:   %3d%%"), round(100*ABS(dbeta)/gmp_real.beta));
	font.color=INT_YELLOW;
	font.y+=18;
	glPrint(&font,_T("estim  dev:   %.3f"), gmp_estim.stdev);
	font.color=INT_ORANGE;
	font.y+=18;
	glPrint(&font,_T("     error:   %3d%%"), round(100*ABS(ddev)/gmp_real.stdev));

	dbeta=gmp_accum.beta-gmp_real.beta;
	ddev=gmp_accum.stdev-gmp_real.stdev;
	font.color=INT_GREEN;
	font.y+=20;
	glPrint(&font,_T("accum beta:   %.3f"), gmp_accum.beta);
	font.color=INT_CYAN;
	font.y+=18;
	glPrint(&font,_T("     error:   %3d%%"), round(100*ABS(dbeta)/gmp_real.beta));
	font.color=INT_GREEN;
	font.y+=18;
	glPrint(&font,_T("accum  dev:   %.3f"), gmp_accum.stdev);
	font.color=INT_CYAN;
	font.y+=18;
	glPrint(&font,_T("     error:   %3d%%"), round(100*ABS(ddev)/gmp_real.stdev));
	font.color=INT_WGREEN;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	return gmp.main(hInstance,hPrevInstance,lpCmdLine,nCmdShow);
}